﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
using System;
using System.Runtime.Serialization;
using System.ComponentModel;

namespace BrainTechLLC
{
    [Serializable]
#if NO_SILVERLIGHT
    [Browsable(true)]
    [TypeConverter(typeof(ExpandableObjectConverter))]
#endif
    [DataContract]
    public class OccupySpaceFloat : PositionFloat, IOccupySpaceFloat
    {
        private SizeFloat _size;
        private LocationFloat[] _vertices;

        public IPositionFloat Position { get { return this as IPositionFloat; } }
        public ISizeFloat Size { get { if (_size == null) _size = new SizeFloat(); return _size; } set { _size = new SizeFloat(value.X, value.Y, value.Z, value.W); } }

        public float XMax { get { return this.X + Size.Length; } }
        public float XMin { get { return this.X; } }
        public float YMax { get { return this.Y + Size.Width; } }
        public float YMin { get { return this.Y; } }
        public float ZMax { get { return this.Z + Size.Height; } }
        public float ZMin { get { return this.Z; } }

        public bool Overlaps(IOccupySpaceFloat otherOccupySpace)
        {
            if (otherOccupySpace.XMin > XMax ||
                otherOccupySpace.YMin > YMax ||
                otherOccupySpace.ZMin > ZMax) return false;

            if (otherOccupySpace.XMax < XMin ||
                otherOccupySpace.YMax < YMin ||
                otherOccupySpace.ZMax < ZMin) return false;

            if (MightOverlapX(otherOccupySpace) && MightOverlapY(otherOccupySpace) && MightOverlapZ(otherOccupySpace))
            {
                return true;
            }

            return false;
        }


        public bool MightOverlapX(IOccupySpaceFloat volumeSpace)
        {
            // O1S  O2S    O1E
            // O1S  O2E    O1E

            // O2S  O1S    O2E
            // O2S  O1E    O2E
            return ((volumeSpace.XMin >= XMin && volumeSpace.XMin < XMax) ||
                  (volumeSpace.XMax > XMin && volumeSpace.XMax <= XMax) ||
                  (XMin >= volumeSpace.XMin && XMin < volumeSpace.XMax) ||
                  (XMax > volumeSpace.XMin && XMax <= volumeSpace.XMax));
        }

        public bool MightOverlapY(IOccupySpaceFloat volumeSpace)
        {
            return ((volumeSpace.YMin >= YMin && volumeSpace.YMin < YMax) ||
                  (volumeSpace.YMax > YMin && volumeSpace.YMax <= YMax) ||
                  (YMin >= volumeSpace.YMin && YMin < volumeSpace.YMax) ||
                  (YMax > volumeSpace.YMin && YMax <= volumeSpace.YMax));
        }

        public bool MightOverlapZ(IOccupySpaceFloat volumeSpace)
        {
            return ((volumeSpace.ZMin >= ZMin && volumeSpace.ZMin < ZMax) ||
                  (volumeSpace.ZMax > ZMin && volumeSpace.ZMax <= ZMax) ||
                  (ZMin >= volumeSpace.ZMin && ZMin < volumeSpace.ZMax) ||
                  (ZMax > volumeSpace.ZMin && ZMax <= volumeSpace.ZMax));
        }



        public ILocationFloat this[Vertices v]
        {
            get
            {
                int vIndex = (int)v;

                if (_vertices == null)
                {
                    _vertices = new LocationFloat[(int)Vertices.TopRightTop + 1];
                }

                if (_vertices[vIndex] == null)
                {
                    float X, Y, Z;
                    switch (v)
                    {
                        // TODO: Angles
                        case Vertices.LowerLeftBottom:
                            X = this.X;
                            Y = this.Y;
                            Z = this.Z;
                            break;
                        case Vertices.LowerLeftTop:
                            X = this.X;
                            Y = this.Y;
                            Z = this.Z + Size.Height;
                            break;
                        case Vertices.LowerRightBottom:
                            X = this.X + Size.Length;
                            Y = this.Y;
                            Z = this.Z;
                            break;
                        case Vertices.LowerRightTop:
                            X = this.X + Size.Length;
                            Y = this.Y;
                            Z = this.Z + Size.Height;
                            break;
                        case Vertices.TopLeftBottom:
                            X = this.X;
                            Y = this.Y + Size.Width;
                            Z = this.Z;
                            break;
                        case Vertices.TopLeftTop:
                            X = this.X;
                            Y = this.Y + Size.Width;
                            Z = this.Z + Size.Height;
                            break;
                        case Vertices.TopRightBottom:
                            X = this.X + Size.Length;
                            Y = this.Y + Size.Width;
                            Z = this.Z;
                            break;
                        case Vertices.TopRightTop:
                            X = this.X + Size.Length;
                            Y = this.Y + Size.Width;
                            Z = this.Z + Size.Height;
                            break;
                        default:
                            throw new Exception("Unknown vertex");
                    }

                    _vertices[vIndex] = new LocationFloat(X, Y, Z);
                }

                return _vertices[vIndex];
            }
        }
    }
}
